﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Windows.Forms;
using FacebookWrapper.ObjectModel;

namespace Desktop_Facebook
{
    internal partial class mainForm : Form
    {
        private const string k_LoggedIn = "Logged in";
        private const string k_LoggedOut = "Logged out";
        private const bool v_AutoLogin = true;
		private const bool v_Checked = true;

		private readonly FetchInfo r_UserInfoFetcher = new FetchInfo();

		private FetchInfo userInfoFetcher 
		{
			get { return r_UserInfoFetcher; }
		}

        public mainForm()
        {
            InitializeComponent();

			Session.Instance.LoggedIn += new LoginEventHandler(Session_LoggedIn);

            userInfoFetcher.ProgressBarInitiator += new FetchInfo.InitProgressBar(progressBarInit);
            userInfoFetcher.ProgressBarUpdater += new FetchInfo.UpdateProgressBar(progressBarUpdate);
            userInfoFetcher.StatusBarUpdater += new FetchInfo.UpdateStatusBar(statusBarUpdate);
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
            ApplicationSettings.Instance.LastWindowState = this.WindowState;
            ApplicationSettings.Instance.LastWindowLocation = this.Location;
            ApplicationSettings.Instance.AutoLogin = this.checkBoxAutoLogin.Checked;
            if (checkBoxAutoLogin.Checked == false)
            {
                ApplicationSettings.Instance.AccessToken = null;
            }

            ApplicationSettings.Instance.Save();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.WindowState = ApplicationSettings.Instance.LastWindowState;
            this.Location = ApplicationSettings.Instance.LastWindowLocation;
            this.checkBoxAutoLogin.Checked = ApplicationSettings.Instance.AutoLogin;

            if (ApplicationSettings.Instance.AutoLogin)
            {
                Session.Instance.Login(v_AutoLogin);
            }
        }

        private void Session_LoggedIn(object sender, LoginEventArgs e)
        {
            if (
                string.IsNullOrEmpty(e.Result.ErrorMessage) && 
                Session.Instance.LoggedInUser != null && 
                Session.Instance.LoggedInUser.Id != null)
            {
                tabControl.Enabled = true;
				buttonLogin.Enabled = false;
				pictureBoxUser.LoadAsync(Session.Instance.LoggedInUser.PictureSqaureURL);
				labelAccountName.Text = Session.Instance.LoggedInUser.Name;
				labelFriendsNumber.Text = Session.Instance.LoggedInUser.Friends.Count.ToString();
				labelThreadNumber.Text = Session.Instance.LoggedInUser.InboxThreads.Count.ToString();
				labelEventsNumber.Text = Session.Instance.LoggedInUser.Events.Count.ToString();
			}
            else
            {
				if (!string.IsNullOrEmpty(e.Result.ErrorMessage))
				{
					MessageBox.Show("Error : " + e.Result.ErrorMessage);
				}
				else 
				{
					MessageBox.Show("Unknown error.");
				}
            }
        }

        private void toggleAllRows(DataGridView i_DataGridView)
        {
            foreach (DataGridViewRow row in i_DataGridView.Rows)
            {
				row.Cells[1].Value = !(bool)row.Cells[1].Value;
            }
        }

        private void buttonSelectAllMessages_Click(object sender, EventArgs e)
        {
            toggleAllRows(gridViewMessages);
        }

        private void buttonBirthdaysSelectAll_Click(object sender, EventArgs e)
        {
            toggleAllRows(gridViewBirthdays);
        }

        private void buttonEventsSelectAll_Click(object sender, EventArgs e)
        {
            toggleAllRows(gridViewEvents);
        }

        private void buttonLogin_Click(object sender, EventArgs e)
        {
            Session.Instance.Login(!v_AutoLogin);
        }

        private void buttonLogout_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void buttonGetEvents_Click(object sender, EventArgs e)
        {
            userInfoFetcher.GetEvents();
            updateGridView(gridViewEvents, userInfoFetcher.EventsTable);
        }

        private void buttonGetBirthdays_Click(object sender, EventArgs e)
        {
            userInfoFetcher.GetBirthdays();
            updateGridView(gridViewBirthdays, userInfoFetcher.BirthdaysTable);
        }

        private void buttonGenerateFriendInteractionStatistics_Click(object sender, EventArgs e)
        {
            userInfoFetcher.GenerateFriendInteractionStatistics();
            updateGridView(gridViewInteractionStatistics, userInfoFetcher.FriendInteractionStatisticsTable);
        }

        private void buttonGetInbox_Click(object sender, EventArgs e)
        {
            userInfoFetcher.GetInbox();
            updateGridView(gridViewMessages, userInfoFetcher.InboxTable);
        }

        private void gridViewBirthdays_SelectionChanged(object sender, EventArgs e)
        {
            if (gridViewBirthdays.CurrentRow != null)
            {
                User friend = gridViewBirthdays.CurrentRow.Cells[0].Value as User;

                labelSelectedFriend.Text = friend.Name;
                pictureBoxFriend.LoadAsync(friend.PictureNormalURL);
            }
        }

		private void messagesGridView_SelectionChanged(object sender, EventArgs e)
		{
            if (gridViewMessages.CurrentRow != null)
            {
                FacebookWrapper.ObjectModel.Message selection = gridViewMessages.CurrentRow.Cells[0].Value as FacebookWrapper.ObjectModel.Message;
				if (selection != null)
				{
					richTextBoxSelectionBody.Text = selection.Text;
				}
            }
		}

        private void gridViewInteractionStatistics_SelectionChanged(object sender, EventArgs e)
        {
            if (gridViewInteractionStatistics.CurrentRow != null)
            {
                User friend = gridViewInteractionStatistics.CurrentRow.Cells[0].Value as User;

                labelWallPostNum.Text = userInfoFetcher.FriendScoreGenerator.Scores[friend.Id].NumberOfWallPosts.ToString();
                labelMessagesNum.Text = userInfoFetcher.FriendScoreGenerator.Scores[friend.Id].NumberOfMessages.ToString();
                labelLikes.Text = userInfoFetcher.FriendScoreGenerator.Scores[friend.Id].NumberOfLikes.ToString();
            }
        }

		private void buttonFilterByText_Click(object sender, EventArgs e)
		{
			string keyword = textBoxTextFilter.Text;

			List<FacebookWrapper.ObjectModel.Message> filter = new MessageFilterer().FilterByPredicate((message) => message != null && message.Text.Contains(keyword));
            userInfoFetcher.PopulateInboxDataTable(filter);
            updateGridView(gridViewMessages, userInfoFetcher.InboxTable);
		}

		private void buttonFilterByDates_Click(object sender, EventArgs e)
		{
			DateTime begin = dateTimePickerFrom.Value;
			DateTime end = dateTimePickerTo.Value;
			List<FacebookWrapper.ObjectModel.Message> filter = new MessageFilterer().FilterByPredicate((message) => (message != null) && (message.CreatedTime >= begin) && (message.CreatedTime <= end));

            userInfoFetcher.PopulateInboxDataTable(filter);
            updateGridView(gridViewMessages, userInfoFetcher.InboxTable);
		}

		private void buttonSaveEventsToCSV_Click(object sender, EventArgs e)
		{
			List<Event> eventsToSave = new List<Event>();
			foreach (DataGridViewRow row in gridViewEvents.Rows)
			{
				if ((bool)row.Cells[1].Value == true)
				{
					Event ev = row.Cells[0].Value as Event;
					if (ev != null) 
					{ 
						eventsToSave.Add(ev); 
					}
				}
			}

			saveFileDialog.FileName = @"Events.csv";
			saveFileDialog.ShowDialog();
			using (FileStream saveFile = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))
			{
				CSVSerializerFactory.Create(eSerializerTypes.Events, eventsToSave).Serialize(saveFile);
			}
		}

		private void buttonSaveBirthdaysToCSV_Click(object sender, EventArgs e)
		{
			Dictionary<string, CustomDate> birthdaysToSave = new Dictionary<string, CustomDate>();
			
            foreach (DataGridViewRow row in gridViewBirthdays.Rows)
			{
				if ((bool)row.Cells[1].Value == true)
				{
					User friend = row.Cells[0].Value as User;
					birthdaysToSave.Add(friend.Id, userInfoFetcher.BirthdayHolder.Birthdays[friend.Id]);
				}
			}
			
			saveFileDialog.FileName = @"Birthdays.csv";
			saveFileDialog.ShowDialog();
			using (FileStream saveFile = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))
			{
				CSVSerializerFactory.Create(eSerializerTypes.Birthdays, birthdaysToSave).Serialize(saveFile);
			}
		}

		private void buttonSaveMessagesToFile_Click(object sender, EventArgs e)
		{
			List<FacebookWrapper.ObjectModel.Message> messagesToSave = new List<FacebookWrapper.ObjectModel.Message>();

			foreach (DataGridViewRow row in gridViewMessages.Rows)
			{
				if ((bool)row.Cells[1].Value == true)
				{
					FacebookWrapper.ObjectModel.Message message = row.Cells[0].Value as FacebookWrapper.ObjectModel.Message;
					messagesToSave.Add(message);
				}
			}

			saveFileDialog.FileName = @"Messages.csv";
			saveFileDialog.ShowDialog();
			using (FileStream saveFile = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write))
			{
				CSVSerializerFactory.Create(eSerializerTypes.Messages, messagesToSave).Serialize(saveFile);
			}
		}

        private void buttonGetAllInfo_Click(object sender, EventArgs e)
        {
			buttonGetAllInfo.Enabled = false;
			userInfoFetcher.NotifyTableReady += new DataTableThreadObserver { OuterInstance = this, DataGridView = gridViewInteractionStatistics, Id = FetchInfo.eTables.FriendInteractionStatistics } .NotifyTableReady;
			userInfoFetcher.NotifyTableReady += new DataTableThreadObserver { OuterInstance = this, DataGridView = gridViewEvents, Id = FetchInfo.eTables.Events } .NotifyTableReady;
			userInfoFetcher.NotifyTableReady += new DataTableThreadObserver { OuterInstance = this, DataGridView = gridViewBirthdays, Id = FetchInfo.eTables.Birthdays } .NotifyTableReady;
			userInfoFetcher.NotifyTableReady += new DataTableThreadObserver { OuterInstance = this, DataGridView = gridViewMessages, Id = FetchInfo.eTables.Inbox } .NotifyTableReady;

			userInfoFetcher.GetAll();
		}

		private class DataTableThreadObserver
		{
			public FetchInfo.eTables Id { get; set; }

			public DataGridView DataGridView { get; set; }
			
			public mainForm OuterInstance { get; set; }
			
			public void NotifyTableReady(DataTable i_DataTable, FetchInfo.eTables i_Id)
			{
				if (i_Id == Id && DataGridView.DataSource == null)
				{
					OuterInstance.updateGridView(DataGridView, i_DataTable);
				}
			}
		}

        private void updateGridView(DataGridView i_DataGridView, DataTable i_DataTable)
        {
            i_DataGridView.BeginInvoke(new Action(() =>
                {
                    i_DataGridView.Columns.Clear();
                    i_DataGridView.DataSource = i_DataTable;
                    i_DataGridView.Columns[0].Visible = false;

                    for (int i = 1; i < i_DataGridView.Columns.Count; i++)
                    {
                        i_DataGridView.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                    }

                    i_DataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
                    i_DataGridView.ReadOnly = true;
                    i_DataGridView.AllowUserToResizeColumns = i_DataGridView.AllowUserToResizeRows = false;
                }));
        }

        private void progressBarUpdate()
        {
            statusStrip.BeginInvoke(new Action(() =>
            {
				if (toolStripProgressBar.Value < toolStripProgressBar.Maximum)
				{
					toolStripProgressBar.Value++;
				}
            }));
        }

        private void progressBarInit(int i_MinValue, int i_MaxValue)
        {
            statusStrip.BeginInvoke(new Action(() =>
            {
                toolStripProgressBar.Value = 0;
                toolStripProgressBar.Minimum = i_MinValue;
                toolStripProgressBar.Maximum = i_MaxValue;
            }));
        }

        private void statusBarUpdate(bool i_Status)
        {
            statusStrip.BeginInvoke(new Action(() =>
            {
                if (i_Status == false)
                {
                    toolStripStatusLabel.Text = "Done";
                }
                else
                {
                    toolStripStatusLabel.Text = "Working...";
                }
            }));
        }
    }
}
